

/*
蓝牙热敏打印机
(算法按列打印,支持换行,...)
 */
import 'package:xsdk_flutter/xsdk/utils/x_utils_log.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_number.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_string.dart';
import 'base/x_utils_print_command_base.dart';
import 'base/x_utils_print_command_esc.dart';
import 'base/x_utils_print_command_tspl.dart';
import 'bean/x_bean_print_column_text.dart';
import 'bean/x_bean_print_label_column_text.dart';
import 'bean/x_bean_label_row.dart';

abstract class XPrinterCommandUtils {

  //(TSPL命令)标签打印 ////////////////////////////////////////////////////////////////////////

  /*
    打印整个标签的命令
    支持文字,条形码,二维码
    200DPI,40mm宽(左从1mm开始)->39*8=314点->24点/中文字 12点/英文-> 314/12 =26英文,即gbk byte长度
    支持按行列打印,可定义多行多列,可指定每行的xy坐标,也可以自动计算xy坐标(从左上角1mm处开始)
    支持文字自动换行(原标签打印机不换行,超出部分则不打了,这里需要算法换行)
    每列都支持文字,条码,二维码,自动计算下一行y坐标,注意:第1列不要是条码(长度不定,无法定位第2列坐标),第1列可以是二维码/文字
    支持文字表格打印

    注意:
    1.使用时,如果数据是每行数据在listData中,那么需要新建一个XBeanLabelRow的list,遍历listData生成XBeanLabelRow,在末尾使用printLabelTSPL组装即可(list转数组);
    2.如果是表格,表格宽度=左右1mm+总byte长度
     */
  static String printLabelTSPL(int labelWidth,//mm 标签宽度
      int labelHeight,//mm 标签高度
      int labelGap,//mm 标签间隔
      int printerDPI, //默认200
      List<XBeanLabelRow>? labelRows){

    if (labelRows==null || labelRows.isEmpty){
      return "";
    }

    if (printerDPI<260){
      printerDPI=200;
    }else{
      printerDPI=300;
    }

    //标签左边从1mm处开始
    labelWidth=labelWidth-1;


    //一张标签通常包含三个部分，即系统设定（1部分）、打印内容设定（2部分）和执行打印指令（3部分）

    StringBuffer sb=StringBuffer();

    //1.1初始化标签大小,间隔,注意:初始化时,要传入实际标签宽度
    String initCommand= XBaseTSPLPrintCommandUtils.getPrintCommand_TSPL(XBaseTSPLPrintCommandUtils.PrintCommand_TSPL_Initialize_SIZE_GAP,[labelWidth+1,labelHeight,labelGap]);
    //1.2打印方向(正向)
    String directionCommand= XBaseTSPLPrintCommandUtils.getPrintCommand_TSPL(XBaseTSPLPrintCommandUtils.PrintCommand_TSPL_DIRECTION,null);
    //1.3打印浓度
    String densityCommand= XBaseTSPLPrintCommandUtils.getPrintCommand_TSPL(XBaseTSPLPrintCommandUtils.PrintCommand_TSPL_DENSITY,[1]);

    //
    sb.write(initCommand);
    sb.write(directionCommand);
    sb.write(densityCommand);

    //2.内容部分
    for(int i=0;i<labelRows.length;i++){

      //上一行
      XBeanLabelRow? preLabelRow;
      //下一行
      XBeanLabelRow? nextLabelRow;
      if (i!=0){
        preLabelRow=labelRows[i-1];
      }

      if (i!=labelRows.length-1){
        nextLabelRow=labelRows[i+1];
      }

      //当前标签行
      XBeanLabelRow labelRow=labelRows[i];

      //开始坐标位置
      int startX=0;
      int startY=0;

      if (labelRow.isUserMarkXY){
        //用户指定开始坐标
        startX=labelRow.startX_dot;
        startY=labelRow.startY_dot+labelRow.paddingTop_Y_dot;

      }else{
        //用户没有指定坐标,按上一行的坐标自动计算
        if (preLabelRow==null){
          //开始位置1mm处
          labelRow.startX_dot=XBasePrintCommandUtils.dot1MM(printerDPI);
          labelRow.startY_dot=XBasePrintCommandUtils.dot1MM(printerDPI);
          //
          startX=labelRow.startX_dot;
          startY=labelRow.startY_dot+labelRow.paddingTop_Y_dot;

        }else{
          //沿用上1行的x坐标,对齐
          labelRow.startX_dot=preLabelRow.startX_dot;
          labelRow.startY_dot=preLabelRow.nextRowY_dot;
          //
          startX=labelRow.startX_dot;
          startY=labelRow.startY_dot+labelRow.paddingTop_Y_dot;
        }
      }

      //每列内容
      List<XBeanLabelColumnText> labelColumnTextList=labelRow.labelColumnTextList;


      //上下行是否画表格
      bool isPreLabelRowDrawLine=false;
      bool isNextLabelRowDrawLine=false;
      if (preLabelRow!=null){
        isPreLabelRowDrawLine=preLabelRow.isDrawTable;
      }
      if (nextLabelRow!=null){
        isNextLabelRowDrawLine=nextLabelRow.isDrawTable;
      }

      //只有1列,自动计算标签宽度,按该行的开始坐标
      if (labelColumnTextList.length==1){
        //
        XBeanLabelColumnText labelColumnText=labelColumnTextList[0];

        if (labelColumnText.isAutoFixColumnWidth){
          //自动计算自定义字体gbk的byte长度按标签宽度计
          int labelCustomTextSizeOneLineGBKBytesLength=0;

          if (labelRow.isDrawTable){
            //画表格ok
            int paddingMm=1+1+1;//表格离标签右边1mm,文字里表格左右1mm
            labelCustomTextSizeOneLineGBKBytesLength=XBasePrintCommandUtils.getLabelCustomTextSizeOneLineStringGBKBytesLength(printerDPI,labelWidth-paddingMm,labelColumnText.textSize);
          }else{
            //不画表格ok
            labelCustomTextSizeOneLineGBKBytesLength=XBasePrintCommandUtils.getLabelCustomTextSizeOneLineStringGBKBytesLength(printerDPI,labelWidth,labelColumnText.textSize);
          }

          labelColumnText.column_textSize_totalBytesLength=labelCustomTextSizeOneLineGBKBytesLength;
        }

        if (labelColumnText.textType==0){
          //文字,支持文字换行,并自动计算下一行y坐标 ok
          handleLabelOneColumn_TextSupportNewLine(
              sb,
              printerDPI,
              labelRow,
              isPreLabelRowDrawLine,
              isNextLabelRowDrawLine,
              startX,
              startY,
              labelColumnText,
              false
          );

        }else if(labelColumnText.textType==1){
          //条形码ok
          String bC= XBaseTSPLPrintCommandUtils.tspl_barcode(
              startX,
              startY,
              labelColumnText.text,
              labelColumnText.isShowBarcodeText,
              labelColumnText.isBarQrcodeMaxHeight,
              labelColumnText.rotation
          );
          sb.write(bC);

          //计算下一行的开始Y坐标ok
          int barcodeHeight=XBasePrintCommandUtils.getLabelBarcodeHeightDots(labelColumnText.isBarQrcodeMaxHeight,labelColumnText.isShowBarcodeText);

          //下一行的开始Y坐标=当前行的y坐标+条码高度+1mm(间隔)
          labelRow.nextRowY_dot=labelRow.startY_dot+labelRow.paddingTop_Y_dot+barcodeHeight+XBasePrintCommandUtils.dot1MM(printerDPI);

        }else if(labelColumnText.textType==2){
          //二维码
          String qC= XBaseTSPLPrintCommandUtils.tspl_qrcode(
              startX,
              startY,
              labelColumnText.isBarQrcodeMaxHeight,
              labelColumnText.text
          );
          sb.write(qC);

          //计算下一行的开始Y坐标ok
          int qrcodeHeight=XBasePrintCommandUtils.getLabelQrcodeHeightDots(labelColumnText.isBarQrcodeMaxHeight);

          //下一行的开始Y坐标=当前行的y坐标+条码高度+1mm(间隔)
          labelRow.nextRowY_dot=labelRow.startY_dot+labelRow.paddingTop_Y_dot+qrcodeHeight+XBasePrintCommandUtils.dot1MM(printerDPI);
        }else if(labelColumnText.textType==3){
          //独立画图片(注意:下一行y坐标不变)

          labelRow.nextRowY_dot=labelRow.startY_dot;

        }else if(labelColumnText.textType==4){
          //独立画方框(注意:下一行y坐标不变)

          String bC= XBaseTSPLPrintCommandUtils.tspl_box(
              labelColumnText.startX,
              labelColumnText.startY,
              labelColumnText.endX,
              labelColumnText.endY,
              labelColumnText.line_thickness
          );
          sb.write(bC);

          labelRow.nextRowY_dot=labelRow.startY_dot;

        }else if(labelColumnText.textType==5){
          //独立画线条(注意:下一行y坐标不变)
          String lC= XBaseTSPLPrintCommandUtils.tspl_line(
              labelColumnText.startX,
              labelColumnText.startY,
              labelColumnText.line_width,
              labelColumnText.line_height
          );
          sb.write(lC);

          labelRow.nextRowY_dot=labelRow.startY_dot;
        }

      }else if (labelColumnTextList.length==2){
        //按第1列宽度,第2列自动剩余宽度

        XBeanLabelColumnText labelColumnText1=labelColumnTextList[0];
        XBeanLabelColumnText labelColumnText2=labelColumnTextList[1];

        if (labelColumnText2.isAutoFixColumnWidth){
          //自动计算自定义字体gbk的byte长度按标签宽度计

          //转为第2列对应字体大小的bytesLength
          int labelCustomTextSizeGBKBytesLength=0;
          if (labelRow.isDrawTable){
            //画表格ok

            int paddingMm=1+1+1+1+1;//表格1的左右边1mm+表格2离左右边各1mm,标签右1mm

            //对应标准字体大小的标签一行字符的长度
            int labelOneLineDefaultTextSizeGBKBytesLength=XBasePrintCommandUtils.getLabelCustomTextSizeOneLineStringGBKBytesLength(printerDPI,labelWidth-paddingMm,0);
            //第1列转为标准字体长度,用于判断
            int labelcolumntext1Defaulttextsizegbkbyteslength= labelCustomTextSizeGBKBytesLength2DefaultTextSizeGBKBytesLength(printerDPI,labelWidth-paddingMm,labelColumnText1.textSize,labelColumnText1.column_textSize_totalBytesLength);
            //标签剩余空间标准字体大小长度
            int labelfreespaceDefaulttextsizegbkbyteslength=labelOneLineDefaultTextSizeGBKBytesLength-labelcolumntext1Defaulttextsizegbkbyteslength;

            labelCustomTextSizeGBKBytesLength= labelDefaultTextSizeGBKBytesLength2CustomTextSizeGBKBytesLength(printerDPI,labelWidth-paddingMm,labelColumnText2.textSize,labelfreespaceDefaulttextsizegbkbyteslength);
          }else{
            //不画表格ok
            //对应标准字体大小的标签一行字符的长度
            int labelOneLineDefaultTextSizeGBKBytesLength=XBasePrintCommandUtils.getLabelCustomTextSizeOneLineStringGBKBytesLength(printerDPI,labelWidth,0);
            //第1列转为标准字体长度,用于判断
            int labelcolumntext1Defaulttextsizegbkbyteslength= labelCustomTextSizeGBKBytesLength2DefaultTextSizeGBKBytesLength(printerDPI,labelWidth,labelColumnText1.textSize,labelColumnText1.column_textSize_totalBytesLength);
            //标签剩余空间标准字体大小长度
            int labelfreespaceDefaulttextsizegbkbyteslength=labelOneLineDefaultTextSizeGBKBytesLength-labelcolumntext1Defaulttextsizegbkbyteslength;

            labelCustomTextSizeGBKBytesLength= labelDefaultTextSizeGBKBytesLength2CustomTextSizeGBKBytesLength(printerDPI,labelWidth,labelColumnText2.textSize,labelfreespaceDefaulttextsizegbkbyteslength);
          }

          labelColumnText2.column_textSize_totalBytesLength=labelCustomTextSizeGBKBytesLength;

        }

        //处理每一列的数据(每列都是纯文字)
        handleLabelMoreColumnTextSupportNewLine(
            sb,
            printerDPI,
            labelRow,
            isPreLabelRowDrawLine,
            isNextLabelRowDrawLine,
            startX,
            startY,
            labelColumnTextList
        );
      }else{
        //多列则按每1列设置的长度计算,处理每一列的数据(每列都是纯文字)
        handleLabelMoreColumnTextSupportNewLine(
            sb,
            printerDPI,
            labelRow,
            isPreLabelRowDrawLine,
            isNextLabelRowDrawLine,
            startX,
            startY,
            labelColumnTextList
        );
      }

    }

    //3.打印输出
    String printCommand= XBaseTSPLPrintCommandUtils.getPrintCommand_TSPL(XBaseTSPLPrintCommandUtils.PrintCommand_TSPL_PRINT,null);
    sb.write(printCommand);

    return sb.toString();
  }


  //(ESC命令)按行列打印 ////////////////////////////////////////////////////////////////////////
  /*
    打印每列内容(补空格对齐,添加到StringBuffer中)
    1.每列的内容超过列宽度时,都支持自动截取拆分,换行打印;
    2.每列独立支持间隔,对齐,字体大小,加粗
    3.支持n列(只要对应纸张1行放得下)
    4.列:n>2列时才判断列宽总和是否超出1行
        n==2以第1列计算,第2列自动重新适应纸张(传入时不用计算)
        n==1,默认自动按纸张重新适配1列宽度(传入时不用计算),也可按标识不自动适配,按传入宽度计算


    58mm,默认字体大小,一行16个中文字(数字字母32个)对应gbk编码bytes数组长度为32
    80mm,默认字体大小,一行24个中文字(数字字母48个)对应gbk编码bytes数组长度为48

    58mm,放大1倍的字体,一行8个中文字(数字字母16个)对应gbk编码bytes数组长度为16
    80mm,放大1倍的字体,一行12个中文字(数字字母24个)对应gbk编码bytes数组长度为24

    58mm,放大1倍的字体,一行5个中文字(数字字母10个)对应gbk编码bytes数组长度为10
    80mm,放大1倍的字体,一行8个中文字(数字字母16个)对应gbk编码bytes数组长度为16

    //如果列内有设置字体大小,测试时打印,如果超过1行会输出提示

    标准字体,4列: printEachColumnTextSupportPrintInRowByNewLine(
                        sb,
                        80,
                        BeanColumnText(19,2,0,false,0,"商品"),
                        BeanColumnText(10,2,0,false,0,"单价"),
                        BeanColumnText(9,2,0,false,0,"数量"),
                        BeanColumnText(10,2,0,false,0,"小计")

    标准字体,2列: printEachColumnTextSupportPrintInRowByNewLine(
                        sb,
                        80,
                        BeanColumnText(6,0,0,false,0,"地址:"), //2个字
                        BeanColumnText(42,0,0,false,0,"地址内容...")

    标准字体,2列: printEachColumnTextSupportPrintInRowByNewLine(
                        sb,
                        80,
                        BeanColumnText(10,0,0,false,0,"实付金额:"), //4个字
                        BeanColumnText(38,0,0,false,0,"0.00") //紧跟

    标准字体,2列: printEachColumnTextSupportPrintInRowByNewLine(
                        sb,
                        80,
                        BeanColumnText(10,0,0,false,0,"实付金额:"), //4个字
                        BeanColumnText(38,0,0,false,2,"0.00") //左右对齐
     */
  static void printEachColumnTextESC(
      StringBuffer sb,
      int paperSize, //纸张尺寸 80mm(一行bytes总长度48), 58mm(一行bytes总长度32)
      bool isEnableTextCustomNewLineChar, //是否识别启用内容中的换行符
      List<XBeanColumnText>? columnTexts
      ){

    if (columnTexts==null || columnTexts.isEmpty){
      return;
    }


    //开头部分: 初始化打印机(清除其他设置,注意:之前的其他未输出的内容缓存也会被清除,在之前的内容结尾要添加(char)10换行输出命令即可)
    String commandInitprinter= XBaseESCPrintCommandUtils.getPrintCommand_ESC(XBaseESCPrintCommandUtils.PrintCommand_ESC_Initialize_Printer,null);
    sb.write(commandInitprinter);

    String commandNewline= XBaseESCPrintCommandUtils.getPrintCommand_ESC(XBaseESCPrintCommandUtils.PrintCommand_ESC_NewLine,null);

    /*
        检查列宽总和是否超过1行
        注意:
        n>2列时才判断列宽总和是否超出1行
        n==2以第1列计算,第2列自动重新适应纸张(传入时不用计算)
        n==1,默认自动按纸张重新适配1列宽度(传入时不用计算),也可按标识不自动适配,按传入宽度计算
         */

    //对应标准字体大小的纸张一行字符的长度
    int paperOneLineDefaultTextSizeGBKBytesLength=XBasePrintCommandUtils.getPaperDefaultTextSizeOneLineStringGBKBytesLength(paperSize);

    if (columnTexts.length>2){
      int sumColumn=0;
      for(XBeanColumnText columnText in columnTexts){
        if (columnText.textSize!=0){
          sumColumn+= customTextSizeGBKBytesLength2DefaultTextSizeGBKBytesLength(paperSize,columnText.textSize,columnText.column_textSize_totalBytesLength);
        }else{
          sumColumn+=columnText.column_textSize_totalBytesLength;
        }
      }
      if (sumColumn>paperOneLineDefaultTextSizeGBKBytesLength){
        XLogUtils.printLog("---设置的列宽总和超过一行宽度,sumColumn=$sumColumn");
        sb.write("---设置的列宽总和超过一行宽度,sumColumn=$sumColumn$commandNewline");
        return;
      }
    }else if (columnTexts.length==2){

      XBeanColumnText columnText1=columnTexts[0];
      XBeanColumnText columnText2=columnTexts[1];

      //第1列转为标准字体长度,用于判断
      int columntext1Defaulttextsizegbkbyteslength= customTextSizeGBKBytesLength2DefaultTextSizeGBKBytesLength(paperSize,columnText1.textSize,columnText1.column_textSize_totalBytesLength);
      //纸张剩余空间标准字体大小长度
      int paperfreespaceDefaulttextsizegbkbyteslength=paperOneLineDefaultTextSizeGBKBytesLength-columntext1Defaulttextsizegbkbyteslength;

      //转为第2列对应字体大小的bytesLength
      int customTextSizeGBKBytesLength= defaultTextSizeGBKBytesLength2CustomTextSizeGBKBytesLength(paperSize,columnText2.textSize,paperfreespaceDefaulttextsizegbkbyteslength);
      columnText2.column_textSize_totalBytesLength=customTextSizeGBKBytesLength;

    }else {
      //只有1列,自动重新适配纸张1行的宽度(方便不用在传入是计算)
      XBeanColumnText columnText1=columnTexts[0];
      //
      int paperCustomTextSizeOneLineGBKBytesLength=XBasePrintCommandUtils.getPaperCustomTextSizeOneLineStringGBKBytesLength(paperSize,columnText1.textSize);
      columnText1.column_textSize_totalBytesLength=paperCustomTextSizeOneLineGBKBytesLength;

    }

    //处理每一列的数据
    for(XBeanColumnText columnText in columnTexts){
      handleEachColumnTextReturnCutText(sb,columnText,isEnableTextCustomNewLineChar);
    }
    //输出已处理好的一行内容
    sb.write(commandNewline);


    //判断是否有截取部分,递归继续换行打印
    bool isHasCutText=false;
    for(XBeanColumnText columnText in columnTexts){
      columnText.text=columnText.cut_text_waitPrint;

      if (!XStringUtils.isEmpty(columnText.cut_text_waitPrint)){
        isHasCutText=true;
      }
    }

    if (isHasCutText){
      //存在
      printEachColumnTextESC(
          sb,
          paperSize,
          isEnableTextCustomNewLineChar,
          columnTexts
      );
    }else{
      //结束(递归),重置打印机,清除和恢复打印机默认设置
      sb.write(commandInitprinter);
    }

  }





  //私有方法///////////////////////////////////////////////////



  //处理多列标签ok
  static void handleLabelMoreColumnTextSupportNewLine(StringBuffer sb,
      int printerDPI,
      XBeanLabelRow labelRow,
      bool isPreLabelRowDrawTable,//上一行是否画表格
      bool isNextLabelRowDrawTable,//下一行是否画表格
      int startxRow,
      int startyRow,
      List<XBeanLabelColumnText> labelColumnTextList){
    //用于计算下一行y坐标
    int maxNextRowY=0;
    //
    int startX=startxRow;
    //
    for (int i=0;i<labelColumnTextList.length;i++){
      //
      XBeanLabelColumnText? preLabelColumnText;
      if (i!=0){
        preLabelColumnText=labelColumnTextList[i-1];
        //X坐标dots,同一行Y坐标不变

        if (preLabelColumnText.textType==0){
          //文字
          //上1列的列宽所占的dots
          int preColumnWidthDots=0;
          if (labelRow.isDrawTable){
            //画表格
            preColumnWidthDots=XBasePrintCommandUtils.dot1MM(printerDPI)+getLabelCustomTextSizeColumnTotalBytesLengthToDots(preLabelColumnText.textSize,preLabelColumnText.column_textSize_totalBytesLength)+XBasePrintCommandUtils.dot1MM(printerDPI);
          }else{
            //非表格
            preColumnWidthDots=getLabelCustomTextSizeColumnTotalBytesLengthToDots(preLabelColumnText.textSize,preLabelColumnText.column_textSize_totalBytesLength);
          }
          //当前列的x坐标
          startX=startX+preColumnWidthDots;


        }else if (preLabelColumnText.textType==1){
          //条码,由于长度不固定,按文字方式
          //上1列的列宽所占的dots
          int preColumnWidthDots=getLabelCustomTextSizeColumnTotalBytesLengthToDots(preLabelColumnText.textSize,preLabelColumnText.column_textSize_totalBytesLength);
          //当前列的x坐标
          startX=startX+preColumnWidthDots;
        }else if (preLabelColumnText.textType==2){
          //二维码
          //上1列中的二维码宽度
          int preColumnQrWidthDots=XBasePrintCommandUtils.getLabelQrcodeHeightDots(preLabelColumnText.isBarQrcodeMaxHeight)+XBasePrintCommandUtils.dot1MM(printerDPI);
          //当前列的x坐标
          startX=startX+preColumnQrWidthDots;
        }

      }
      XBeanLabelColumnText labelColumnText=labelColumnTextList[i];

      //下一行y坐标
      int nextRowY=handleLabelEachColumnTextSupportNewLine(
          sb,
          printerDPI,
          labelRow,
          isPreLabelRowDrawTable,
          isNextLabelRowDrawTable,
          startX,
          startyRow,
          labelColumnText,
          false
      );

      //以最大的为准,作为计算下一行
      if (nextRowY>maxNextRowY){
        maxNextRowY=nextRowY;
      }
    }

    //下1行y坐标
    labelRow.nextRowY_dot=maxNextRowY+XBasePrintCommandUtils.dot1MM(printerDPI);


    //画表格
    if (labelRow.isDrawTable){

      //左线
      String lineCommandLeft= XBaseTSPLPrintCommandUtils.tspl_line(
          startxRow,
          startyRow,
          labelRow.line_thickness,
          labelRow.nextRowY_dot-startyRow
      );
      sb.write(lineCommandLeft);


      //右线
      int jsSumcolumnwidth=0;
      int jsColumnrightx=0;

      for (int i=0;i<labelColumnTextList.length;i++){

        XBeanLabelColumnText labelColumnText=labelColumnTextList[i];

        //
        jsSumcolumnwidth+=XBasePrintCommandUtils.dot1MM(printerDPI)
            +getLabelCustomTextSizeColumnTotalBytesLengthToDots(labelColumnText.textSize,labelColumnText.column_textSize_totalBytesLength)
            +XBasePrintCommandUtils.dot1MM(printerDPI);

        jsColumnrightx=startxRow+jsSumcolumnwidth-labelRow.line_thickness;

        //
        String lineCommandRight= XBaseTSPLPrintCommandUtils.tspl_line(
            jsColumnrightx,
            startyRow,
            labelRow.line_thickness,
            labelRow.nextRowY_dot-startyRow //
        );

        sb.write(lineCommandRight);
      }

      //上线
      String tableLineCommandTop= XBaseTSPLPrintCommandUtils.tspl_line(
          startxRow,
          XNumberUtils.d2int_floor(startyRow-labelRow.line_thickness/2),
          jsSumcolumnwidth-labelRow.line_thickness,
          labelRow.line_thickness
      );

      sb.write(tableLineCommandTop);

      //下线
      if (!isNextLabelRowDrawTable){
        //下1行不是表格,结束表格,画表格底线
        String lineCommandBottom= XBaseTSPLPrintCommandUtils.tspl_line(
            startxRow,
            labelRow.nextRowY_dot-labelRow.line_thickness,//不影响下1行空间
            jsSumcolumnwidth-labelRow.line_thickness,
            labelRow.line_thickness
        );
        sb.write(lineCommandBottom);
      }

    }

  }


  //处理标签每1列,支持文字换行(递归),返回下一行y坐标
  static int handleLabelEachColumnTextSupportNewLine(StringBuffer sb,
      int printerDPI,
      XBeanLabelRow labelRow,
      bool isPreLabelRowDrawTable,//上一行是否画表格
      bool isNextLabelRowDrawTable,//下一行是否画表格
      int startX,
      int startY,
      XBeanLabelColumnText labelColumnText,
      bool isLabelColumnTextNewLinePrint //是否当前列内容换行打印
      ){
    //init
    labelColumnText.cut_text_print ="";
    labelColumnText.cut_text_waitPrint ="";

    //算法留空的列间隔大小,列宽的间隔距离至少需要有一个中文字符的空间,否则算法无法截取显示(2个单位为1个中文字的大小距离/2个单位为2个字母或数字大小距离)
    int realByteslengthColumn=labelColumnText.column_textSize_totalBytesLength - labelColumnText.column_space_bytes;
    if (realByteslengthColumn >=2){
      if (!XStringUtils.isEmpty(labelColumnText.text)){


        if (labelColumnText.textType==1){
          // 属于条码

          //条码高度
          int currentBarcodeHeight=XBasePrintCommandUtils.getLabelBarcodeHeightDots(labelColumnText.isBarQrcodeMaxHeight,labelColumnText.isShowBarcodeText);

          String bC= XBaseTSPLPrintCommandUtils.tspl_barcode(
              startX,
              startY,
              labelColumnText.text,
              labelColumnText.isShowBarcodeText,
              labelColumnText.isBarQrcodeMaxHeight,
              labelColumnText.rotation

          );
          sb.write(bC);

          //清除,退出递归
          labelColumnText.text="";

          //返回下一行y坐标
          return startY+currentBarcodeHeight;


        }else if (labelColumnText.textType==2){
          // 属于二维码

          //二维码高度
          int currentQrcodeHeight=XBasePrintCommandUtils.getLabelQrcodeHeightDots(labelColumnText.isBarQrcodeMaxHeight);

          String qC= XBaseTSPLPrintCommandUtils.tspl_qrcode(
              startX,
              startY,
              labelColumnText.isBarQrcodeMaxHeight,
              labelColumnText.text
          );
          sb.write(qC);

          //清除,退出递归
          labelColumnText.text="";

          //返回下一行y坐标
          return startY+currentQrcodeHeight;

        }else if(labelColumnText.textType==3){
          //独立画图片(注意:下一行y坐标不变)

          return labelRow.startY_dot;
        }else if(labelColumnText.textType==4){
          //独立画方框(注意:下一行y坐标不变)
          String bC= XBaseTSPLPrintCommandUtils.tspl_box(
              labelColumnText.startX,
              labelColumnText.startY,
              labelColumnText.endX,
              labelColumnText.endY,
              labelColumnText.line_thickness
          );
          sb.write(bC);

          return labelRow.startY_dot;
        }else if(labelColumnText.textType==5){
          //独立画线条(注意:下一行y坐标不变)
          String lC= XBaseTSPLPrintCommandUtils.tspl_line(
              labelColumnText.startX,
              labelColumnText.startY,
              labelColumnText.line_width,
              labelColumnText.line_height
          );
          sb.write(lC);

          return labelRow.startY_dot;
        }

        // 属于文字/////////////////////////////////////////////////

        //文字的xy坐标
        int startTextX=startX;
        int startTextY=startY;


        //画表格,则文字坐标
        if (labelRow.isDrawTable){
          startTextX+=XBasePrintCommandUtils.dot1MM(printerDPI);
          if (!isLabelColumnTextNewLinePrint){
            //不是当前表格换行(换行则按正常间隔startY)
            startTextY+=XBasePrintCommandUtils.dot1MM(printerDPI);
          }
        }

        //如果有画表格,则存在间隔
        int linePaddingY=startTextY-startY;

        //当前高度
        int currentTextHeight=XBasePrintCommandUtils.getLabelChineseCharTextWidthOrHeightDots(labelColumnText.textSize);

        //清除所有内容中的特殊字符(换行等)
        labelColumnText.text = replaceNotGoodSpecialChar(labelColumnText.text);

        //
        if (XBasePrintCommandUtils.getBytesLength_GBK(labelColumnText.text)<=realByteslengthColumn){
          //没有超过列的宽度(显示字数宽度)

          //全截取
          labelColumnText.cut_text_print= labelColumnText.text;

          if (labelColumnText.align==0){
            //左对齐,不用处理
          }else if (labelColumnText.align==1){
            //居中对齐
            String leftSpace=getCenterAlignSpaceForColumn(realByteslengthColumn,labelColumnText.cut_text_print);
            labelColumnText.cut_text_print=leftSpace+labelColumnText.cut_text_print;

          }else if (labelColumnText.align==2){
            //右对齐
            String leftSpace=getColumnFreeSpace(realByteslengthColumn,labelColumnText.cut_text_print);
            labelColumnText.cut_text_print=leftSpace+labelColumnText.cut_text_print;
          }

          //
          String tC= XBaseTSPLPrintCommandUtils.tspl_text(
              startTextX,
              startTextY,
              labelColumnText.cut_text_print,
              labelColumnText.textSize,
              labelColumnText.rotation
          );
          sb.write(tC);

          //清除,退出递归
          labelColumnText.text="";

          //返回下一行y坐标
          return startY+currentTextHeight+linePaddingY;

        }else{

          //超过列的宽度(显示字数宽度),按中文字数长度截取(1个中文字占2个单位长度)

          //获取最接近满列宽度的截取下标值
          int cutIndex=getCutTextIndex(realByteslengthColumn,labelColumnText.text);
          //
          labelColumnText.cut_text_print =labelColumnText.text.substring(0,cutIndex);
          //截取剩余未打印部分,递归时,换行处理打印
          labelColumnText.cut_text_waitPrint =labelColumnText.text.substring(cutIndex).trim();

          if (labelColumnText.align==0){
            //左对齐,不用处理
          }else if (labelColumnText.align==1){
            //居中对齐
            String leftSpace=getCenterAlignSpaceForColumn(realByteslengthColumn,labelColumnText.cut_text_print);
            labelColumnText.cut_text_print=leftSpace+labelColumnText.cut_text_print;
          }else if (labelColumnText.align==2){
            //右对齐
            String leftSpace=getColumnFreeSpace(realByteslengthColumn,labelColumnText.cut_text_print);
            labelColumnText.cut_text_print=leftSpace+labelColumnText.cut_text_print;
          }

          //
          String tC= XBaseTSPLPrintCommandUtils.tspl_text(
              startTextX,
              startTextY,
              labelColumnText.cut_text_print,
              labelColumnText.textSize,
              labelColumnText.rotation
          );
          sb.write(tC);

          //
          if (!XStringUtils.isEmpty(labelColumnText.cut_text_waitPrint)){
            //递归,换行
            labelColumnText.text=labelColumnText.cut_text_waitPrint;

            //递归下一行y开始坐标
            int newLineStartY=startY+currentTextHeight+linePaddingY+XNumberUtils.d2int_floor(XBasePrintCommandUtils.dot1MM(printerDPI)/2);//内容未完换行间隔不要太大

            //返回最新的下一行y坐标
            int nextRowY=handleLabelEachColumnTextSupportNewLine(
                sb,
                printerDPI,
                labelRow,
                isPreLabelRowDrawTable,
                isNextLabelRowDrawTable,
                startX,
                newLineStartY,
                labelColumnText,
                true
            );

            //返回下一行y坐标
            return nextRowY;

          }else{

            //清除,退出递归
            labelColumnText.text="";
            //返回下一行y坐标
            return startY+currentTextHeight+linePaddingY;
          }

        }

      }

    }

    //返回下一行y坐标
    return startY;
  }



  //当标签只有1列时,处理文字换行(递归) ok
  static void handleLabelOneColumn_TextSupportNewLine(StringBuffer sb,
      int printerDPI,
      XBeanLabelRow labelRow,
      bool isPreLabelRowDrawTable,//上一列是否画表格
      bool isNextLabelRowDrawTable,//下一列是否画表格
      int startX,
      int startY,
      XBeanLabelColumnText labelColumnText,
      bool isLabelColumnTextNewLinePrint //是否当前列内容换行打印
      ){

    //init
    labelColumnText.cut_text_print ="";
    labelColumnText.cut_text_waitPrint ="";

    //文字的xy坐标
    int startTextX=startX;
    int startTextY=startY;

    //画表格,则文字坐标
    if (labelRow.isDrawTable){

      startTextX+=XBasePrintCommandUtils.dot1MM(printerDPI);

      if (!isLabelColumnTextNewLinePrint){
        //不是当前表格换行(换行则按正常间隔startY)
        startTextY+=XBasePrintCommandUtils.dot1MM(printerDPI);
      }

      if (!isLabelColumnTextNewLinePrint){
        //不是当前列换行打印,画表格顶部线
        String tableLineCommandTop= XBaseTSPLPrintCommandUtils.tspl_line(
            startX,
            XNumberUtils.d2int_floor(startY-labelRow.line_thickness/2),
            XBasePrintCommandUtils.dot1MM(printerDPI)+getLabelCustomTextSizeColumnTotalBytesLengthToDots(labelColumnText.textSize,labelColumnText.column_textSize_totalBytesLength)+XBasePrintCommandUtils.dot1MM(printerDPI)-labelRow.line_thickness,
            labelRow.line_thickness
        );

        sb.write(tableLineCommandTop);
      }
    }

    //如果有画表格,则存在间隔
    int linePaddingY=startTextY-startY;

    //当前列的总字数长度gbk->byte
    int columnTextsizeTotalbyteslength=labelColumnText.column_textSize_totalBytesLength;
    //算法留空的列间隔大小,列宽的间隔距离至少需要有一个中文字符的空间,否则算法无法截取显示(2个单位为1个中文字的大小距离/2个单位为2个字母或数字大小距离)
    int realByteslengthColumn=columnTextsizeTotalbyteslength-labelColumnText.column_space_bytes;

    //
    if (realByteslengthColumn >=2){

      if (!XStringUtils.isEmpty(labelColumnText.text)){
        //清除所有内容中的特殊字符(换行等)
        labelColumnText.text = replaceNotGoodSpecialChar(labelColumnText.text);
        //
        if (XBasePrintCommandUtils.getBytesLength_GBK(labelColumnText.text)<=realByteslengthColumn){
          //没有超过列的宽度(显示字数宽度)
          //截取
          labelColumnText.cut_text_print= labelColumnText.text;

          if (labelColumnText.align==0){
            //左对齐,不用处理
          }else if (labelColumnText.align==1){
            //居中对齐
            String leftSpace=getCenterAlignSpaceForColumn(realByteslengthColumn,labelColumnText.cut_text_print);
            labelColumnText.cut_text_print=leftSpace+labelColumnText.cut_text_print;

          }else if (labelColumnText.align==2){
            //右对齐
            String leftSpace=getColumnFreeSpace(realByteslengthColumn,labelColumnText.cut_text_print);
            labelColumnText.cut_text_print=leftSpace+labelColumnText.cut_text_print;
          }

          //
          String tC= XBaseTSPLPrintCommandUtils.tspl_text(
              startTextX,
              startTextY,
              labelColumnText.cut_text_print,
              labelColumnText.textSize,
              labelColumnText.rotation
          );
          sb.write(tC);

          //清除,退出递归
          labelColumnText.text="";

          //计算下一行的开始Y坐标ok
          int textHeight=XBasePrintCommandUtils.getLabelChineseCharTextWidthOrHeightDots(labelColumnText.textSize);

          //下一行的开始Y坐标=当前行的y坐标+条码高度+1mm(间隔)
          if (labelRow.nextRowY_dot==0){
            labelRow.nextRowY_dot=labelRow.startY_dot+labelRow.paddingTop_Y_dot+textHeight+linePaddingY+XBasePrintCommandUtils.dot1MM(printerDPI);
          }else{
            labelRow.nextRowY_dot=labelRow.nextRowY_dot+textHeight+linePaddingY+XBasePrintCommandUtils.dot1MM(printerDPI);
          }


        }else{
          //超过列的宽度(显示字数宽度),按中文字数长度截取(1个中文字占2个单位长度)

          //获取最接近满列宽度的截取下标值
          int cutIndex=getCutTextIndex(realByteslengthColumn,labelColumnText.text);
          //
          labelColumnText.cut_text_print =labelColumnText.text.substring(0,cutIndex);
          //截取剩余未打印部分,递归时,换行处理打印
          labelColumnText.cut_text_waitPrint =labelColumnText.text.substring(cutIndex).trim();

          if (labelColumnText.align==0){
            //左对齐,不用处理
          }else if (labelColumnText.align==1){
            //居中对齐
            String leftSpace=getCenterAlignSpaceForColumn(realByteslengthColumn,labelColumnText.cut_text_print);
            labelColumnText.cut_text_print=leftSpace+labelColumnText.cut_text_print;
          }else if (labelColumnText.align==2){
            //右对齐
            String leftSpace=getColumnFreeSpace(realByteslengthColumn,labelColumnText.cut_text_print);
            labelColumnText.cut_text_print=leftSpace+labelColumnText.cut_text_print;
          }

          //
          String tC= XBaseTSPLPrintCommandUtils.tspl_text(
              startTextX,
              startTextY,
              labelColumnText.cut_text_print,
              labelColumnText.textSize,
              labelColumnText.rotation
          );
          sb.write(tC);


          if (!XStringUtils.isEmpty(labelColumnText.cut_text_waitPrint)){

            //递归,换行
            labelColumnText.text=labelColumnText.cut_text_waitPrint;

            //计算下一行的开始Y坐标ok
            int textHeight=XBasePrintCommandUtils.getLabelChineseCharTextWidthOrHeightDots(labelColumnText.textSize);
            //下一行的开始Y坐标=当前行的y坐标+条码高度+1mm(间隔)
            if (labelRow.nextRowY_dot==0){
              labelRow.nextRowY_dot=labelRow.startY_dot+labelRow.paddingTop_Y_dot+textHeight+linePaddingY+XNumberUtils.d2int_floor(XBasePrintCommandUtils.dot1MM(printerDPI)/2);//内容未完换行间隔不要太大
            }else{
              labelRow.nextRowY_dot=labelRow.nextRowY_dot+textHeight+linePaddingY+XNumberUtils.d2int_floor(XBasePrintCommandUtils.dot1MM(printerDPI)/2);//内容未完换行间隔不要太大
            }

            //递归
            handleLabelOneColumn_TextSupportNewLine(
                sb,
                printerDPI,
                labelRow,
                isPreLabelRowDrawTable,
                isNextLabelRowDrawTable,
                startX,
                labelRow.nextRowY_dot,
                labelColumnText,
                true
            );

          }else{
            //清除,退出递归
            labelColumnText.text="";

            //计算下一行的开始Y坐标ok
            int textHeight=XBasePrintCommandUtils.getLabelChineseCharTextWidthOrHeightDots(labelColumnText.textSize);
            //下一行的开始Y坐标=当前行的y坐标+条码高度+1mm(间隔)
            if (labelRow.nextRowY_dot==0){
              labelRow.nextRowY_dot=labelRow.startY_dot+labelRow.paddingTop_Y_dot+textHeight+linePaddingY+XBasePrintCommandUtils.dot1MM(printerDPI);
            }else{
              labelRow.nextRowY_dot=labelRow.nextRowY_dot+textHeight+linePaddingY+XBasePrintCommandUtils.dot1MM(printerDPI);
            }

          }

        }

        //是否画表格
        if (labelRow.isDrawTable){
          //此行只有1列,判断上1行和下1行是否画线情况

          String lineCommandLeft= XBaseTSPLPrintCommandUtils.tspl_line(
              startX,
              startY,
              labelRow.line_thickness,
              labelRow.nextRowY_dot-startY
          );
          String lineCommandRight= XBaseTSPLPrintCommandUtils.tspl_line(
              startX+XBasePrintCommandUtils.dot1MM(printerDPI)+getLabelCustomTextSizeColumnTotalBytesLengthToDots(labelColumnText.textSize,labelColumnText.column_textSize_totalBytesLength)+XBasePrintCommandUtils.dot1MM(printerDPI)-labelRow.line_thickness,
              startY,
              labelRow.line_thickness,
              labelRow.nextRowY_dot-startY
          );

          sb.write(lineCommandLeft);
          sb.write(lineCommandRight);


          if (!isNextLabelRowDrawTable){
            //下1行不是表格,结束表格,画表格底线
            String lineCommandBottom= XBaseTSPLPrintCommandUtils.tspl_line(
                startX,
                labelRow.nextRowY_dot-labelRow.line_thickness,//不影响下1行空间
                XBasePrintCommandUtils.dot1MM(printerDPI)+getLabelCustomTextSizeColumnTotalBytesLengthToDots(labelColumnText.textSize,labelColumnText.column_textSize_totalBytesLength)+XBasePrintCommandUtils.dot1MM(printerDPI)-labelRow.line_thickness,
                labelRow.line_thickness
            );

            sb.write(lineCommandBottom);

          }

        }

      }else{
        //空白

        //下一行的开始Y坐标=当前行的y坐标+条码高度+1mm(间隔)
        if (labelRow.nextRowY_dot==0){
          labelRow.nextRowY_dot=labelRow.startY_dot+labelRow.paddingTop_Y_dot+0+linePaddingY+XBasePrintCommandUtils.dot1MM(printerDPI);
        }else{
          labelRow.nextRowY_dot=labelRow.nextRowY_dot+0+linePaddingY+XBasePrintCommandUtils.dot1MM(printerDPI);
        }
      }

    }

  }




  //当前标签列总宽占多少dots
  static int getLabelCustomTextSizeColumnTotalBytesLengthToDots(
      int textSize,
      int columnTextsizeTotalbyteslength
      ){
    //中文字
    int oneChineseCharWidth=XBasePrintCommandUtils.getLabelChineseCharTextWidthOrHeightDots(textSize);
    //英文数字
    int oneEnglishCharWidth=XNumberUtils.d2int_floor(oneChineseCharWidth/2);

    return columnTextsizeTotalbyteslength*oneEnglishCharWidth;

  }


  /*
    标签标准字体大小的长度转换成对应字体大小的长度,用于计算判断是否超出纸张一行的宽度
    参数:
    int printerDPI 打印机DPI 200/300
    int labelWidth, 标签宽度 40mm
    int textSize,  0 标准大小, 1放大1倍, 2 放大2倍
    int defaultTextSize_BytesLength, 标准字体大小的bytes的长度
     */
  static int labelDefaultTextSizeGBKBytesLength2CustomTextSizeGBKBytesLength(
      int printerDPI,
      int labelWidth,
      int textSize,
      int defaulttextsizeByteslength){


    if (textSize==0){
      //标准字体,不用转换
      return defaulttextsizeByteslength;
    }

    //标签标准字体大小一行字符的长度
    int labelOneLineDefaultTextSizeGBKBytesLength=XBasePrintCommandUtils.getLabelCustomTextSizeOneLineStringGBKBytesLength(printerDPI,labelWidth,0);

    //计算比例
    double scale= XNumberUtils.d2d(2,defaulttextsizeByteslength/labelOneLineDefaultTextSizeGBKBytesLength);

    //标签一行的对应字体大小长度
    int labelOneLineCustomTextSizeStringGBKBytesLength=XBasePrintCommandUtils.getLabelCustomTextSizeOneLineStringGBKBytesLength(printerDPI,labelWidth,textSize);

    int customTextSizeGBKBytesLength = XNumberUtils.d2int(scale*labelOneLineCustomTextSizeStringGBKBytesLength);
    XLogUtils.printLog("---标准字体大小转换自定义字体大小所占的长度计算,textSize=$textSize,defaultTextSize_BytesLength=$defaulttextsizeByteslength,customTextSizeGBKBytesLength=$customTextSizeGBKBytesLength");

    return customTextSizeGBKBytesLength;

  }

  /*
    标签自定义字体大小的长度转换成对应标准大小的长度,用于计算判断是否超出纸张一行的宽度
    参数:
    int printerDPI 打印机DPI 200/300
    int labelWidth, 标签宽度 40mm
    int textSize,  0 标准大小, 1放大1倍, 2 放大2倍
    int column_textSize_BytesLength, 列中的一行显示对应字体大小的bytes的长度
     */
  static int labelCustomTextSizeGBKBytesLength2DefaultTextSizeGBKBytesLength(
      int printerDPI,
      int labelWidth,
      int textSize,
      int columnTextsizeByteslength){

    if (textSize==0){
      //标准字体大小,不用转换
      return columnTextsizeByteslength;
    }

    //标签标准字体大小一行字符的长度
    int labelOneLineDefaultTextSizeGBKBytesLength=XBasePrintCommandUtils.getLabelCustomTextSizeOneLineStringGBKBytesLength(printerDPI,labelWidth,0);

    //标签一行的对应字体大小长度
    int labelOneLineCustomTextSizeStringGBKBytesLength=XBasePrintCommandUtils.getLabelCustomTextSizeOneLineStringGBKBytesLength(printerDPI,labelWidth,textSize);

    //计算比例
    double scale= XNumberUtils.d2d(2,columnTextsizeByteslength/labelOneLineCustomTextSizeStringGBKBytesLength);

    int defaultTextSizeGBKBytesLength = XNumberUtils.d2int_floor(scale*labelOneLineDefaultTextSizeGBKBytesLength);

    XLogUtils.printLog("---自定义字体大小转换标准字体大小所占的长度计算,textSize=$textSize,column_textSize_BytesLength=$columnTextsizeByteslength,defaultTextSizeGBKBytesLength=$defaultTextSizeGBKBytesLength");

    return defaultTextSizeGBKBytesLength;

  }


  //处理当前列的文字内容,截取处理超出的内容,并添加当前截取部分的内容到StringBuffer
  static void handleEachColumnTextReturnCutText(
      StringBuffer sb,
      XBeanColumnText currentColumnText,//当前列的内容
      bool isEnableTextCustomNewLineChar //是否识别启用内容中的换行符
      ){

    //init
    currentColumnText.cut_text_print ="";
    currentColumnText.cut_text_waitPrint ="";

    //算法留空的列间隔大小,列宽的间隔距离至少需要有一个中文字符的空间,否则算法无法截取显示(2个单位为1个中文字的大小距离/2个单位为2个字母或数字大小距离)
    int realByteslengthColumn=currentColumnText.column_textSize_totalBytesLength - currentColumnText.column_space_bytes;
    if (realByteslengthColumn >=2){

      //是否加粗字体
      if (currentColumnText.isTextBold){
        //加粗字体
        String commandBold1= XBaseESCPrintCommandUtils.getPrintCommand_ESC(XBaseESCPrintCommandUtils.PrintCommand_ESC_Text_bold,[1]);
        sb.write(commandBold1);
      }
      if (currentColumnText.textSize==1){
        //放大1倍
        String commandTextsize= XBaseESCPrintCommandUtils.getPrintCommand_ESC(XBaseESCPrintCommandUtils.PrintCommand_ESC_Text_Size,[1]);
        sb.write(commandTextsize);
      }else if (currentColumnText.textSize==2){
        //放大2倍
        String commandTextsize= XBaseESCPrintCommandUtils.getPrintCommand_ESC(XBaseESCPrintCommandUtils.PrintCommand_ESC_Text_Size,[2]);
        sb.write(commandTextsize);
      }else{
        //默认大小
        String commandTextsize= XBaseESCPrintCommandUtils.getPrintCommand_ESC(XBaseESCPrintCommandUtils.PrintCommand_ESC_Text_Size,[0]);
        sb.write(commandTextsize);
      }


      if (!XStringUtils.isEmpty(currentColumnText.text)){

        if (!isEnableTextCustomNewLineChar){
          //不识别启用内容中的换行符,清除所有内容中的特殊字符(换行等)
          currentColumnText.text = replaceNotGoodSpecialChar(currentColumnText.text);
        }else{
          //启用,拦截转义符,由算法处理,否则打印机识别换行会影响对齐
          currentColumnText.text = initSpecialChar(currentColumnText.text);
        }

        if (XBasePrintCommandUtils.getBytesLength_GBK(currentColumnText.text)<=realByteslengthColumn){
          //没有超过列的宽度(显示字数宽度)
          //currentColumnText.cut_text_print =currentColumnText.text;

          //开头,判断是否存在换行符等特殊字符,识别删除开头部分所有特殊字符,避免影响同一行其他列的打印
          currentColumnText.text=cleanStartAllSpecialChar(currentColumnText.text);

          //已处理开头换行符,获取内容中的第一个换行符下标
          int cutIndex=getFirstNewlineCharIndex(currentColumnText.text);
          if (cutIndex!=-1){
            //存在换行
            currentColumnText.cut_text_print =currentColumnText.text.substring(0,cutIndex);
            //清除其他所有特殊字符,避免影响同一行其他列的打印
            currentColumnText.cut_text_print = replaceNotGoodSpecialChar(currentColumnText.cut_text_print);

            //截取剩余未打印部分,递归时,换行处理打印
            currentColumnText.cut_text_waitPrint =currentColumnText.text.substring(cutIndex);
            //再次处理剩余部分,仅存在换行等特殊字符,则不再处理
            currentColumnText.cut_text_waitPrint=handleEndText(currentColumnText.cut_text_waitPrint);
          }else{
            //不存在换行
            currentColumnText.cut_text_print= replaceNotGoodSpecialChar(currentColumnText.text);
          }


          if (currentColumnText.align==0){
            //左对齐,不用处理
          }else if (currentColumnText.align==1){
            //居中对齐
            String leftSpace=getCenterAlignSpaceForColumn(realByteslengthColumn,currentColumnText.cut_text_print);
            sb.write(leftSpace);

          }else if (currentColumnText.align==2){
            //右对齐
            String leftSpace=getColumnFreeSpace(realByteslengthColumn,currentColumnText.cut_text_print);
            sb.write(leftSpace);
          }

          //
          sb.write(currentColumnText.cut_text_print);
        }else{
          //超过列的宽度(显示字数宽度),按中文字数长度截取(1个中文字占2个单位长度)

          //开头,判断是否存在换行符等特殊字符,识别删除开头部分所有特殊字符,避免影响同一行其他列的打印
          currentColumnText.text=cleanStartAllSpecialChar(currentColumnText.text);

          //获取最接近满列宽度的截取下标值
          int cutIndex=getCutTextIndex(realByteslengthColumn,currentColumnText.text);

          //已处理开头换行符,获取内容中的第一个换行符下标
          int firstNewlineCharIndex=getFirstNewlineCharIndex(currentColumnText.text);
          if (firstNewlineCharIndex!=-1){
            //存在
            if (firstNewlineCharIndex<cutIndex){
              //则以内容中的换行下标为准换行
              cutIndex=firstNewlineCharIndex;
            }
          }

          //
          currentColumnText.cut_text_print =currentColumnText.text.substring(0,cutIndex);
          //清除其他所有特殊字符,避免影响同一行其他列的打印
          currentColumnText.cut_text_print = replaceNotGoodSpecialChar(currentColumnText.cut_text_print);


          //截取剩余未打印部分,递归时,换行处理打印
          currentColumnText.cut_text_waitPrint =currentColumnText.text.substring(cutIndex);
          //再次处理剩余部分,仅存在换行等特殊字符,则不再处理
          currentColumnText.cut_text_waitPrint=handleEndText(currentColumnText.cut_text_waitPrint);


          if (currentColumnText.align==0){
            //左对齐,不用处理
          }else if (currentColumnText.align==1){
            //居中对齐
            String leftSpace=getCenterAlignSpaceForColumn(realByteslengthColumn,currentColumnText.cut_text_print);
            sb.write(leftSpace);

          }else if (currentColumnText.align==2){
            //右对齐
            String leftSpace=getColumnFreeSpace(realByteslengthColumn,currentColumnText.cut_text_print);
            sb.write(leftSpace);
          }

          //
          sb.write(currentColumnText.cut_text_print);

        }


        if (currentColumnText.align==1){
          //居中对齐

          //左右空格
          String leftRightSpace=getCenterAlignSpaceForColumn(realByteslengthColumn,currentColumnText.cut_text_print);

          //右边剩余空间补空格对齐(用于下1列对齐)
          String rightSpace= getColumnFreeSpace(currentColumnText.column_textSize_totalBytesLength,leftRightSpace+currentColumnText.cut_text_print);
          sb.write(rightSpace);

        }else if (currentColumnText.align==2){
          //右对齐

          //左空格
          String leftSpace=getColumnFreeSpace(realByteslengthColumn,currentColumnText.cut_text_print);
          //右边剩余空间补空格对齐(用于下1列对齐)
          String rightSpace= getColumnFreeSpace(currentColumnText.column_textSize_totalBytesLength,leftSpace+currentColumnText.cut_text_print);
          sb.write(rightSpace);

        }else{
          //左对齐
          //右边剩余空间补空格对齐(用于下1列对齐)
          String rightSpace= getColumnFreeSpace(currentColumnText.column_textSize_totalBytesLength,currentColumnText.cut_text_print);
          sb.write(rightSpace);
        }

      }else{

        //当前列的内容空白,需要补齐当前列宽度的空格,避免相隔n列不能对齐
        String space= getColumnFreeSpace(currentColumnText.column_textSize_totalBytesLength,null);
        sb.write(space);
      }


      //结束恢复//////////////////////////////////
      // 是否加粗字体
      if (currentColumnText.isTextBold){
        //取消加粗字体
        String commandBold0= XBaseESCPrintCommandUtils.getPrintCommand_ESC(XBaseESCPrintCommandUtils.PrintCommand_ESC_Text_bold,[0]);
        sb.write(commandBold0);
      }

      //恢复默认字体大小
      if (currentColumnText.textSize!=0){
        String commandTextsize= XBaseESCPrintCommandUtils.getPrintCommand_ESC(XBaseESCPrintCommandUtils.PrintCommand_ESC_Text_Size,[0]);
        sb.write(commandTextsize);
      }

    }

  
  }

  //初始化和支持的转义符,在算法中处理换行,不传递到打印机中识别换行,避免对齐问题
  static String initSpecialChar(String text){
    if (!XStringUtils.isEmpty(text)) {
      text=text.replaceAll("\\n","\n");
      text=text.replaceAll("\\r","\r");
      text=text.replaceAll("\\t","\t");
      text=text.replaceAll("\\f","\f");
      text=text.replaceAll("\\b","\b");
      text=text.replaceAll("\\","");//不支持忽略\,注意:也不能转为/,否则会有问题
    }
    return text;
  }

  //清除开头所有特殊字符(递归)
  static String cleanStartAllSpecialChar(String text){

    if (text.startsWith("\n")){
      text=text.replaceFirst("\n","");
    }
    if (text.startsWith("\r")){
      text=text.replaceFirst("\r","");
    }
    if (text.startsWith("\t")){
      text=text.replaceFirst("\t","");
    }
    if (text.startsWith("\f")){
      text=text.replaceFirst("\f","");
    }
    if (text.startsWith("\b")){
      text=text.replaceFirst("\b","");
    }

    if (text.startsWith("\n")
        ||text.startsWith("\r")
        ||text.startsWith("\t")
        ||text.startsWith("\f")
        ||text.startsWith("\b")
    ){
      return cleanStartAllSpecialChar(text);
    }

    return text;
  }

  /*
    获得第1个换行符的下标(递归),
    注意:开头部分已处理,已不存在换行符
     */
  static int getFirstNewlineCharIndex(String text){

    if (text.contains("\n")
        ||text.contains("\r")
    ){

      int firstNewlineCharIndex= text.indexOf("\n");
      if (firstNewlineCharIndex==-1){
        //不存在
        firstNewlineCharIndex= text.indexOf("\r");
      }

      //
      if (firstNewlineCharIndex!=-1){

        String t=text.substring(0,firstNewlineCharIndex);
        //再次判断
        if (t.contains("\n")
            ||t.contains("\r")
        ){
          return getFirstNewlineCharIndex(t);
        }

        return firstNewlineCharIndex;
      }
    }

    return -1;

  }

  //处理剩余部分,仅存在换行等特殊字符,则不再处理
  static String handleEndText(String text){

    String newText= replaceNotGoodSpecialChar(text);
    if (XStringUtils.isEmpty(newText)){
      //
      return "";
    }

    return text;
  }


  /*
     * 处理会影响对齐问题的多余特殊字符,如/t  /////n
     * */
  static String replaceNotGoodSpecialChar(String str) {
    String dest = "";
    dest=str.replaceAll("\\n","\n");
    dest=dest.replaceAll("\\r","\r");
    dest=dest.replaceAll("\\t","\t");
    dest=dest.replaceAll("\\f","\f");
    dest=dest.replaceAll("\\b","\b");
    dest=dest.replaceAll("\\","");//不支持忽略\,注意:也不能转为/,否则会有问题
    dest=str.replaceAll("\n","");
    dest=str.replaceAll("\r","");
    dest=str.replaceAll("\t","");
    dest=str.replaceAll("\f","");
    dest=str.replaceAll("\b","");
      return dest;
  }


  //
  /*
    由于gbk的中文bytes和英文/数字的bytes个数的对应长度不一样,递归尽可能截取打满一行宽度的内容
    注意:调用此方法,totalText的长度>ColumnGBKBytesLength,因此不用判断
     */
  static int getCutTextIndex(int realColumnGBKBytesLength,String totalText){

    //先按中文字符截取
    int cutIndex=XNumberUtils.d2int_floor(realColumnGBKBytesLength/2);
    //
    cutIndex=checkCutTextIndex(realColumnGBKBytesLength,totalText,cutIndex,false);

    return cutIndex;

  }


  //递归获得最接近满宽度
  static int checkCutTextIndex(int ColumnGBKBytesLength,String totalText,int cutIndex,bool isLastCut){


    //避免下标溢出
    if (totalText.length==cutIndex){
      return cutIndex;
    }

    //字符截取
    String cutText=totalText.substring(0,cutIndex);
    //截取部分的bytes长度
    int bytesLength=XBasePrintCommandUtils.getBytesLength_GBK(cutText);

    if (isLastCut){
      return cutIndex;
    }else{

      if (bytesLength==ColumnGBKBytesLength){
        //刚好
        return cutIndex;
      }

      //
      if (bytesLength<ColumnGBKBytesLength){
        //少于,尝试下标+1再次截取
        cutIndex=cutIndex+1;
        return checkCutTextIndex(ColumnGBKBytesLength,totalText,cutIndex,false);

      }else{
        //大于,则下标-1,结束递归
        cutIndex=cutIndex-1;
        return checkCutTextIndex(ColumnGBKBytesLength,totalText,cutIndex,true);
      }
    }

  }


  /*
     采用空格方法补齐当前列的宽度,用于对齐下一列
     int columnTotalLength: 当前列所占的字符gbk编码byte数组的长度
     String columnText: 当前列的字符串内容
     */
  static String getColumnFreeSpace(
      int columnTextGBKBytesLength,
      String? columnText
      ){

    int spaceLength=0;
    if (columnText!=null){
      int preStringLength=XBasePrintCommandUtils.getBytesLength_GBK(columnText);
      if (columnTextGBKBytesLength>preStringLength){
        spaceLength=columnTextGBKBytesLength-preStringLength;
      }
    }else{
      spaceLength=columnTextGBKBytesLength;
    }

    if (spaceLength<=0){
      return "";
    }

    StringBuffer sb=StringBuffer();
    for (int i=0;i<spaceLength;i++){
      sb.write(" ");
    }
    return sb.toString();
  }


  /*
    自定义字体大小的长度转换成对应标准大小的长度,用于计算判断是否超出纸张一行的宽度
    参数:
    int paperSize, 纸张 58mm 80mm
    int textSize,  0 标准大小, 1放大1倍, 2 放大2倍
    int column_textSize_BytesLength, 列中的一行显示对应字体大小的bytes的长度
     */
  static int customTextSizeGBKBytesLength2DefaultTextSizeGBKBytesLength(
      int paperSize,
      int textSize,
      int columnTextsizeByteslength){

    if (textSize==0){
      //标准字体大小,不用转换
      return columnTextsizeByteslength;
    }

    //纸张一行的对应字体大小长度
    int paperOneLineCustomTextSizeStringGBKBytesLength=XBasePrintCommandUtils.getPaperCustomTextSizeOneLineStringGBKBytesLength(paperSize,textSize);

    //纸张一行的标准字体大小长度
    int paperOneLineDefaultTextSizeStringGBKBytesLength=XBasePrintCommandUtils.getPaperDefaultTextSizeOneLineStringGBKBytesLength(paperSize);

    //计算比例
    double scale= XNumberUtils.d2d(2,columnTextsizeByteslength/paperOneLineCustomTextSizeStringGBKBytesLength);

    int defaultTextSizeGBKBytesLength = XNumberUtils.d2int_floor(scale*paperOneLineDefaultTextSizeStringGBKBytesLength);

    XLogUtils.printLog("---自定义字体大小转换标准字体大小所占的长度计算,textSize=$textSize,column_textSize_BytesLength=$columnTextsizeByteslength,defaultTextSizeGBKBytesLength=$defaultTextSizeGBKBytesLength");

    return defaultTextSizeGBKBytesLength;

  }

  /*
    标准字体大小的长度转换成对应字体大小的长度,用于计算判断是否超出纸张一行的宽度
    参数:
    int paperSize, 纸张 58mm 80mm
    int textSize,  0 标准大小, 1放大1倍, 2 放大2倍
    int defaultTextSize_BytesLength, 标准字体大小的bytes的长度
     */
  static int defaultTextSizeGBKBytesLength2CustomTextSizeGBKBytesLength(
      int paperSize,
      int textSize,
      int defaulttextsizeByteslength){


    //纸张一行的标准字体大小长度
    int paperOneLineDefaultTextSizeStringGBKBytesLength=XBasePrintCommandUtils.getPaperDefaultTextSizeOneLineStringGBKBytesLength(paperSize);

    if (textSize==0){
      //标准字体,不用转换
      return defaulttextsizeByteslength;
    }

    //计算比例
    double scale= XNumberUtils.d2d(2,defaulttextsizeByteslength/paperOneLineDefaultTextSizeStringGBKBytesLength);

    //纸张一行的对应字体大小长度
    int paperOneLineCustomTextSizeStringGBKBytesLength=XBasePrintCommandUtils.getPaperCustomTextSizeOneLineStringGBKBytesLength(paperSize,textSize);

    int customTextSizeGBKBytesLength = XNumberUtils.d2int_floor(scale*paperOneLineCustomTextSizeStringGBKBytesLength);
    XLogUtils.printLog("---标准字体大小转换自定义字体大小所占的长度计算,textSize=$textSize,defaultTextSize_BytesLength=$defaulttextsizeByteslength,customTextSizeGBKBytesLength=$customTextSizeGBKBytesLength");

    return customTextSizeGBKBytesLength;

  }


  static String getCenterAlignSpaceForColumn(int columnTextGBKBytesLength,String? str){

    int center = XNumberUtils.d2int_floor((columnTextGBKBytesLength-XBasePrintCommandUtils.getBytesLength_GBK(str))/2);
    if (center>0){
      StringBuffer sb=StringBuffer();
      for (int i = 0; i<center; i++){
        sb.write(" ");
      }
      return sb.toString();
    }
    return "";
  }


/////////////////////////////////////////////////////////////////////////////




}
